package com.bsj.media.media;

public class Adpcm {
	// 16
	static int indexTable[] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 };
	// 89
	static int stepsizeTable[] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55,
			60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494,
			544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
			3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289,
			16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 };

	/**
	 * 解码adpcm数据
	 * 
	 * @param audioBuf
	 * @param length
	 * @param pcm
	 * @return
	 */
	public static int decoder(byte[] audioBuf, int inOffset, int length, byte[] pcm) {
		if (audioBuf == null) {
			return 0;
		}

		short stateValprev = (short) (audioBuf[inOffset] + (audioBuf[inOffset + 1] << 8)); /* Previous output value */
		byte stateIndex = audioBuf[inOffset + 2]; /* Index into stepsize table */

		inOffset += 4;
		int in_len = length - 4;

		int outOffset = 0;
		int i = 0;
		byte tmp_data;
		long step;/* Quantizer step size */
		long predsample;/* Output of ADPCM predictor */
		long diffq;/* Dequantized predicted difference */
		int index;/* Index into step size table */

		int Samp;
		byte SampH, SampL;
		byte inCode;

		/*
		 * Restore previous values of predicted sample and quantizer step size index
		 */
		predsample = stateValprev;
		index = stateIndex;

		byte[] realAudioBuf = new byte[in_len];
		System.arraycopy(audioBuf, inOffset, realAudioBuf, 0, in_len);

		for (i = 0; i < in_len * 2; i++) {
			tmp_data = realAudioBuf[i / 2];
			if (i % 2 != 0) {
				inCode = (byte) ((tmp_data & 0xf0) >> 4);
			} else {
				inCode = (byte) (tmp_data & 0x0f);
			}

			if (index > stepsizeTable.length - 1 || index < 0) {
				continue;
			}

			step = stepsizeTable[index];
			/*
			 * Inverse quantize the ADPCM code into a predicted difference using the
			 * quantizer step size
			 */

			diffq = step >> 3;
			if ((inCode & 4) != 0) {
				diffq += step;
			}
			if ((inCode & 2) != 0) {
				diffq += (step >> 1);
			}
			if ((inCode & 1) != 0) {
				diffq += (step >> 2);
			}
			/*
			 * Fixed predictor computes new predicted sample by adding the old predicted
			 * sample to predicted difference
			 */
			if ((inCode & 8) != 0) {
				predsample -= diffq;
			} else {
				predsample += diffq;
			}
			/*
			 * Check for overflow of the new predicted sample
			 */
			if (predsample > 32767) {
				predsample = 32767;
			} else if (predsample < -32768) {
				predsample = -32768;
			}
			/*
			 * Find new quantizer stepsize index by adding the old index to a table lookup
			 * using the ADPCM code
			 */
			if (inCode < 0 || inCode > indexTable.length - 1) {
				continue;
			}

			index += indexTable[inCode];
			/*
			 * Check for overflow of the new quantizer step size index
			 */
			if (index < 0) {
				index = 0;
			}
			if (index > 88) {
				index = 88;
			}

			/* Return the new ADPCM code */
			Samp = (int) predsample;
			if (Samp >= 0) {
				SampH = (byte) (Samp / 256);
				SampL = (byte) (Samp - 256 * SampH);
			} else {
				Samp = 32768 + Samp;
				SampH = (byte) (Samp / 256);
				SampL = (byte) (Samp - 256 * SampH);
				SampH += 0x80;
			}

			pcm[outOffset++] = SampL;
			pcm[outOffset++] = SampH;
		}

		return outOffset;
	}

	private static short saturate(int amp) {
		short amp16;
		/* Hopefully this is optimised for the common case - not clipping */
		amp16 = (short) amp;
		if (amp == amp16) {
			return amp16;
		}
		if (amp > Short.MAX_VALUE) {
			return Short.MAX_VALUE;
		}
		return Short.MIN_VALUE;
	}

	// 无符号 byte
	private static byte interEncode(ima_adpcm_state_s state, short linear) {
		int e;
		int ss;
		int adpcm;
		int diff;
		int initial_e;

		ss = stepsizeTable[state.step_index];
		initial_e = linear - state.last;
		e = initial_e;
		diff = ss >> 3;
		adpcm = (byte) 0x00;
		if (e < 0) {
			adpcm = (byte) 0x08;
			e = -e;
		}
		if (e >= ss) {
			adpcm |= (byte) 0x04;
			e -= ss;
		}
		ss >>= 1;
		if (e >= ss) {
			adpcm |= (byte) 0x02;
			e -= ss;
		}
		ss >>= 1;
		if (e >= ss) {
			adpcm |= (byte) 0x01;
			e -= ss;
		}

		if (initial_e < 0) {
			diff = -(diff - initial_e - e);
		} else {
			diff = diff + initial_e - e;
		}

		state.last = saturate(diff + state.last);
		state.step_index += indexTable[adpcm & 0x07];
		if (state.step_index < 0) {
			state.step_index = 0;
		} else if (state.step_index > 88) {
			state.step_index = 88;
		}

		return (byte) (adpcm & 0xFF);
	}

	/**
	 * adpcm 编码
	 * 
	 * @param s
	 * @param ima_data
	 * @param imaOffset
	 * @param amp
	 * @param len
	 * @return 返回编码后数据长度
	 */
	public static int encoder(ima_adpcm_state_s s, byte ima_data[], int imaOffset, final byte amp[], int len) {
		int i = 0;
		int bytes = imaOffset;

		ima_data[bytes++] = (byte) (amp[0] & 0xFF);
		ima_data[bytes++] = (byte) (amp[1] & 0xFF);
		ima_data[bytes++] = (byte) (s.step_index & 0xFF);
		ima_data[bytes++] = 0;
		s.last = ((amp[0] & 0xFF) + (amp[1] << 8));
		s.bits = 0;

		for (; i < len; i += 2) {
			short temp = (short) ((amp[i] & 0xFF) + (amp[i + 1] << 8));
			int temp2 = ((s.ima_byte & 0xFF) >> 4);
			int temp3 = interEncode(s, temp) << 4;
			s.ima_byte = (byte) ((temp2 | temp3) & 0xFF);
			if ((s.bits++ & 1) != 0) {
				ima_data[bytes++] = (byte) (s.ima_byte & 0x00FF);
			}
		}

		return (bytes - imaOffset);
	}
}
